﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace SimpleCsv
{
    class ParseHelper
    {
        public static object Parse(String s, Type type, IFormatProvider formatProvider = null)
        {
            if (formatProvider == null) { formatProvider = CultureInfo.InvariantCulture; }

            // Nullables
            if (type.IsGenericType && type.Name.StartsWith("Nullable"))
            {
                if (String.IsNullOrEmpty(s)) { return null; }
                type = type.GetGenericArguments()[0];
            }

            if (typeof(string) == type) { return s; }
            //if (typeof(DateTime) == type) { return ParseDateTime(s); }
            if (type.IsEnum) { return Enum.Parse(type, s); }
            if (IsList(type)) { return ParseList(s, type); }

            // Default: Invoke the parse method
            // Try first with InvariantCulture specified



            try
            {
                MethodInfo m = type.GetMethod("Parse", new Type[] { typeof(string), typeof(IFormatProvider) });
                if (m != null)
                {
                    return m.Invoke(null, new object[] { s, formatProvider });
                }
                // If above n/a, with no culture
                m = type.GetMethod("Parse", new Type[] { typeof(string) });
                if (m != null)
                {
                    return m.Invoke(null, new object[] { s });
                }
            }
            catch (TargetInvocationException e)
            {
                throw new FormatException("Invalid format of '" + s + "' ex: \r\n" + e.InnerException);
            }

            throw new InvalidOperationException("No Parse(string, IFormatProvider) method on type: " + type.FullName);
        }

        static bool IsList(Type t)
        {
            Type[] args = t.GetGenericArguments();
            return typeof(IList).IsAssignableFrom(t) && args != null && args.Length == 1;
        }

        public static IList ParseList(string s, Type listType, char delimiterChar = ',', char quoteChar='"')
        {
            Type elemType = listType.GetGenericArguments()[0];
            IList list = (IList)Activator.CreateInstance(listType);

            // Empty list
            if (String.IsNullOrEmpty(s)) { return list; }

            var elems = CsvReader.DecodeRow(s, delimiterChar, quoteChar);

            foreach (String elem in elems)
            {
                object el = Parse(elem, elemType);
                list.Add(el);
            }
            return list;
        }

    }
}
